﻿#include "WindowManager.h"

#include "Framework/Application.h"

#include "Render/RenderContext.h"
#include "Time/CPUTimeCounter.h"

static RWindowManager *GWindowManager=nullptr;

void RWindowManager::Initialize()
{
    GetApplication()->MakeSureInitialized<RRenderContext>();
    GWindowManager=this;
}

void RWindowManager::Deinitialize()
{
    GWindowManager=nullptr;
}

RWindowManager *RWindowManager::Get()
{
    return GWindowManager;
};

void RWindowManager::Tick(float DeltaSeconds)
{
    TVector<RWindowPtr> WindowToClose;
    for(auto& Window: Windows)
    {
        if(Window->IsClosed())
        {
            WindowToClose.Add(Window);
        }
    }

    

    for(auto& Window : WindowToClose)
    {
        WH::DestroyObject(Window.Get()); //will auto unregister from window manager in window destructor
    }

    for(auto& Window: Windows)
    {
        Window->Tick(DeltaSeconds);
    }
    
   

}
// bool RWindowManager::ProcessEvent(const SystemEvent &InEvent)
// {
//     if(InEvent.IsA<SMouseButtonEvent>())
//     {
//         return ProcessMouseEvent(InEvent.Get<SMouseButtonEvent>());
//     }
//     else if(InEvent.IsA<SKeyboardEvent>())
//     {
//         return ProcessKeyboardEvent(InEvent.Get<SKeyboardEvent>());
//     }
//     else if(InEvent.IsA<STextInputEvent>())
//     {
//         return ProcessTextInput(InEvent.Get<STextInputEvent>());
//     }
//     else if(InEvent.IsA<SWindowEvent>())
//     {
//         return ProcessWindowEvent(InEvent.Get<SWindowEvent>());
//     }
//     else
//     {
//         assert(false && "Unimplement");
//         return false;
//     }
// };

void RWindowManager::PaintWindows()
{
    CODE_BLOCK_TIME_COUNT(U"绘制窗口")

    if(RRenderContext::Get()->OccupyWritableBuffer())
    {
        for(auto& Window: Windows)
        {
            Window->PaintWidgets();
        }

        TVector<std::shared_ptr<CRenderSurface>> RenderSurfaces;
        for(auto& Window: Windows)
        {
            RenderSurfaces.Add(Window->RenderSurface);
        }

        RRenderContext::Get()->WriteSurfaces(RenderSurfaces);
        RRenderContext::Get()->ReleaseOccupiedWritingBuffer();
    }

}

bool RWindowManager::ProcessWindowEvent(const SWindowEvent &InEvent)
{
    if(!ModalWindows.empty())
    {
        auto ModalWindow=ModalWindows.top();
        if(InEvent.GetWindowID()==ModalWindow->GetWindowID())
        {
            return ModalWindow->ProcessWindowEvent(InEvent);
        }
        else if(InEvent.GetType()==EWindowEventType::ClickDisabled)
        {
            ModalWindow->NotifyBlinkModalWindow();
            return false;
        }

        return false;
    }

    for(auto It=Windows.rbegin();It!=Windows.rend();It++)
    {
        auto Window=*It;
        if(InEvent.GetWindowID()==Window->GetWindowID()  && Window->ProcessWindowEvent(InEvent))
        {
            return true;
        }

        //modal window consume all event
        if(Window->bIsModalWindow)
        {
            break;
        }

    }

    return false;
}

bool RWindowManager::ProcessMouseEvent(const SMouseButtonEvent &MouseEvent)
{
    if(!ModalWindows.empty())
    {
        auto ModalWindow=ModalWindows.top();
        if(MouseEvent.GetWindowID()==ModalWindow->GetWindowID())
        {
            return ModalWindow->ProcessMouseEvent(MouseEvent);
        }

        return false;
    }

    //cant directly use Windows, because window may be created during event process
    //that will cause iterator invalid
    auto CurrentWindows=Windows;

    for(auto It=CurrentWindows.rbegin();It!=CurrentWindows.rend();It++)
    {
        auto Window=*It;
        if(MouseEvent.GetWindowID()==Window->GetWindowID()  && Window->ProcessMouseEvent(MouseEvent))
        {
            return true;
        }

    }

    return false;

}

void RWindowManager::MakeWindowModal(RWindowPtr InWindow)
{
    InWindow->bIsModalWindow=true;
    ModalWindows.push(InWindow);

    //record is other window enabled and diable all other window
    TMap<RWindowPtr,bool> WindowEnabled;
    for(auto& Window: Windows)
    {
        if(Window==InWindow)
        {
            continue;
        }

        bool bEnabled=Window->IsWindowEnabled();
        if(!bEnabled)
        {
            continue;
        }
        WindowEnabled.Add(Window,bEnabled);
        Window->EnableWindow(false);
    }

    while(InWindow && !InWindow->IsClosed())
    {
        GetApplication()->RunOnce();
    }

    //restore other window enabled
    for(auto& Pair: WindowEnabled)
    {
        Pair.Key->EnableWindow(Pair.Value);
    }


    if(!ModalWindows.empty()&&ModalWindows.top()==InWindow)
    {
        ModalWindows.pop();
    }

}

bool RWindowManager::HasAnyWindow()
{
    return !Windows.Empty();
}

void RWindowManager::RegisterWindow(RWindowPtr InWindow)
{
    Windows.Add(InWindow);
}

void RWindowManager::UnregisterWindow(RWindowPtr InWindow)
{
    Windows.Remove(InWindow);
  
}

